package com.ls.fw.token.interceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.ModelAndView;

import com.alibaba.fastjson.JSON;
import com.ls.fw.data.bean.ResultTemplate;
import com.ls.fw.mvc.springmvc.support.interceptor.BaseInterceptor;
import com.ls.fw.mvc.springmvc.util.ViewUtil;
import com.ls.fw.token.annotation.RequireToken;
import com.ls.fw.token.handler.HttpTokenHandler;
import com.ls.fw.token.support.Token;
import com.ls.fw.web.core.servlet.utils.JsonUtils;
import com.ls.fw.web.core.servlet.utils.UrlUtils;


/**
 *  token 拦截器
 * @author lisheng
 * @date 2015年11月28日 下午3:53:04
 * @version V1.0
 */
public class TokenInterceptor extends BaseInterceptor {
	
    private HttpTokenHandler tokenHandler;

    private String name = "_tokenObj";
    /**
     * token存在则返回true
     */
    private boolean okIfExist = true;

    private boolean validMethod(RequireToken annotation, HttpServletRequest request){
    	boolean valid = true;
    	if(annotation != null){
    		String[]  method = annotation.ignoreMethod();
    		boolean ok = isExist(request, method,false);
    		if(ok){
    			valid = false;
    		}else{
    			valid = false;
    			method = annotation.acceptMethod();
    			ok = isExist(request, method,true);
    			if(ok){
    				valid = true;
    			}
    		}
    	}
    	return valid;
    }

	
	/**
	 * 
	 * @author lisheng
	 * @date 2016年2月28日 下午10:58:23
	 * @version V1.0
	 * @param request
	 * @param method
	 */
	private boolean isExist(HttpServletRequest request, String[] method, boolean defaultValue) {
		boolean ok = defaultValue;
		if(method != null && method.length>0){
			ok = false;
			for (String string : method) {
				if (request.getMethod().equalsIgnoreCase(string)) {
					ok = true;
		    	}
			}
		}
		return ok;
	}
    
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    	 boolean valid = true;
    	 if (open && handler instanceof HandlerMethod) {
			 HandlerMethod method = (HandlerMethod) handler;
	         RequireToken annotation = method.getMethodAnnotation(RequireToken.class);
	         annotation = annotation==null?method.getBeanType().getAnnotation(RequireToken.class):annotation;
	         if (annotation != null 
	        		 && (annotation.name().equals(tokenHandler.getTokenRepository().getParameterName())
	        				 ||annotation.name().equals(tokenHandler.getTokenRepository().getHeaderName()))
	        		 && this.validMethod(annotation, request)) {
	        	 valid = false;
	             String token = "";
	             token = getToken(request);
	             if(null != tokenHandler){
	                boolean ok = false;
	                if(org.apache.commons.lang3.StringUtils.isNotBlank(token)){
	                	boolean exist = tokenHandler.checkToken(request,token);
	                    if(exist && okIfExist){
	                    	ok = true;
	                    }else if(!exist && !okIfExist){
	                    	ok = true;
	                    }
		            }
	            	if(ok){
	     				this.tokenHandler.success(request, response, token, annotation);
	     				valid = true;
	     			}else{
	     				ResponseBody body = null;
     		            if(method != null){
     		                body = method
     		                    .getMethodAnnotation(ResponseBody.class);
     		                if(body==null){
     		                	body = method.getBeanType().getAnnotation(ResponseBody.class);
     		                }
     		            }
	     		        boolean ajax = ViewUtil.isReturnJson(request,false);
	     		        if(body != null){
	     		            ajax = true;
	     		        }
	     				this.tokenHandler.fail(request, response, token);
	     				if(ajax){
	     					// 设置ContentType
	     					response.setContentType(MediaType.APPLICATION_JSON_VALUE);
	     					// 避免乱码
	     					response.setCharacterEncoding("UTF-8");
	     					response.setHeader("Cache-Control", "no-cache, must-revalidate");
	     					ResultTemplate r =  ResultTemplate.newInstance();
	     					r.setMsg(getTipName()+"值无效！");
	     					r.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
	     					JsonUtils.sendJsonData(response, JSON.toJSONString(r));
	     				}else{
	     					response.sendError(HttpServletResponse.SC_UNAUTHORIZED,getTipName()+"值无效！");
	     				}
	     				if (logger.isWarnEnabled()) {
	     					logger.warn("Invalid token ("+token+")found for "
	     							+ UrlUtils.buildFullRequestUrl(request));
	     				}
	     			}
	     		}
	         } 
    	 }
        return valid;
    }

	private String getTipName(){
		StringBuilder name = new StringBuilder();
		name.append(this.tokenHandler.getTokenRepository().getHeaderName());
		name.append("/"+this.tokenHandler.getTokenRepository().getParameterName());
		return name.toString();
	}
	/**
	 * 
	 * @author lisheng
	 * @date 2016年2月28日 下午10:51:47
	 * @version V1.0
	 * @param request
	 * @return
	 */
	private String getToken(HttpServletRequest request) {
		String token;
		token = request.getHeader(tokenHandler.getTokenRepository().getHeaderName());
		 if(org.apache.commons.lang3.StringUtils.isBlank(token)){
		 	token = request.getParameter(tokenHandler.getTokenRepository().getParameterName());
		 }
		return token;
	}

	public void setTokenHandler(HttpTokenHandler tokenHandler) {
		this.tokenHandler = tokenHandler;
	}

	public boolean isOkIfExist() {
		return okIfExist;
	}

	public void setOkIfExist(boolean okIfExist) {
		this.okIfExist = okIfExist;
	}


	@Override
	public void postHandle(HttpServletRequest request,
			HttpServletResponse response, Object handler,
			ModelAndView modelAndView) throws Exception {
		super.postHandle(request, response, handler, modelAndView);
		Token t = tokenHandler.getTokenRepository().loadToken(request, false);
	    if(t!=null && modelAndView != null){
	    	modelAndView.addObject(name,t);
	    	response.setHeader(tokenHandler.getTokenRepository().getHeaderName(),t.getToken());
	    }
	}


	public String getName() {
		return name;
	}


	public void setName(String name) {
		this.name = name;
	}
}
